#!/bin/sh
#
#
# cvmfs-publish manages lvm snapshots for publishing cvmfs repositories.
#
# SYNOPSIS
# cvmfs-publish <repository_name> <command> [<snapshot>]
#
# AUTHOR
# Jakob Blomer, jakob.blomer@cern.ch
#
# CREATED
# March 2010

usage ()
{
    /bin/echo "Usage: cvmfs-publish <command> [<snapshot>]                   "
    /bin/echo
    /bin/echo "Example:                                                      "
    /bin/echo "  cvmfs-publish publish                                       "
    /bin/echo
    /bin/echo "Commands:                                                     "
    /bin/echo "  publish: creates a snapshot from the current working volume " 
    /bin/echo "           and publishes it.                                  "
    /bin/echo "  switch:  publish another snapshot.                          "
    /bin/echo "  remove:  removes a snapshot.                                "
    /bin/echo "  list:    shows all snapshots.                               " 
    /bin/echo
}


CVMFS_WEBFS_TARGET=/srv/www/webfs

. /etc/cvmfsdrc
if [ -f /etc/cvmfsdrc.local ]; then
  . /etc/cvmfsdrc.local
fi

for reqvar in CVMFS_VG CVMFS_LV_TRUNK
do
   eval value=\$$reqvar
   if [ -z "$value" ]; then
      /bin/echo "Set a value for $reqvar in /etc/cvmfsdrc"
      exit 1
   fi
done

if [ ! -z "$CVMFS_LVM_ROTATE" ]; then
  if [ $CVMFS_LVM_ROTATE -lt 2 ]; then
    /bin/echo "CVMFS_LVM_ROTATE has to be at least 2"
    exit 1
  fi
fi

LVS=/usr/sbin/lvs
LVCREATE=/usr/sbin/lvcreate
LVREMOVE=/usr/sbin/lvremove

for tools in LVS LVCREATE LVREMOVE
do
  eval this_tool=\$$tools
  if [ ! -x "$LVS" ]; then
    /bin/echo "$this_tool is not available"  
  fi
done

if [ $# -lt 1 ]; then
  usage
  exit
fi

COMMAND=$1

# returns: 0 - not s snapshot, 1 - snapshot (not published), 2 - snapshot (published)
check_snapshot ()
{
  snapshot=$1  
  
  $LVS --noheadings -o origin /dev/$CVMFS_VG/$snapshot | /bin/grep "$CVMFS_LV_TRUNK" > /dev/null
  if [ $? -eq 0 ]; then
    /bin/grep $snapshot /etc/fstab > /dev/null
    if [ $? -eq 0 ]; then
      return 2
    else
      return 1
    fi  
  else
    return 0
  fi  
}

switch_snapshot ()
{
  snapshot=$1
  
  fstabline="/dev/$CVMFS_VG/$snapshot $CVMFS_WEBFS_TARGET ext3 defaults,ro 0 0 #CVMFS_AUTOPUBLISH"
  /bin/grep -v CVMFS_AUTOPUBLISH /etc/fstab > /etc/fstab.2
  /bin/echo $fstabline >> /etc/fstab.2
  /bin/mv /etc/fstab.2 /etc/fstab
    
  /bin/umount $CVMFS_WEBFS_TARGET 2>/dev/null
  /bin/mount $CVMFS_WEBFS_TARGET
}


list_snapshots()
{
  snapshots=`/bin/ls /dev/$CVMFS_VG/ 2>/dev/null`
  if [ $? -ne 0 ]; then 
    /bin/echo "LVM volume group $CVMFS_VG does not exist." 
    exit
  fi
  for s in $snapshots
  do
    check_snapshot $s
    result=$?
    if [ $result -eq 1 ]; then
      /bin/echo $s
     elif [ $result -eq 2 ]; then
       /bin/echo "$s (published)"
     fi
  done
}

remove_snapshot()
{
  snapshot=$1
  check_snapshot $snapshot
  
  result=$?
  if [ $result -eq 0 ]; then
    /bin/echo "This is not a snapshot."
    exit
  elif [ $result -eq 2 ]; then 
    /bin/echo "Cannot remove published snapshot."
    exit
  fi
  $LVREMOVE -f /dev/$CVMFS_VG/$snapshot
}


case $COMMAND in
  list)
    list_snapshots    
  ;;
  publish)
    origin="/dev/$CVMFS_VG/$CVMFS_LV_TRUNK"
    /bin/ls $origin &> /dev/null
    if [ $? -ne 0 ]; then 
      /bin/echo "LVM volume group for $REPOSITORY does not exist." 
      exit
    fi
    size=`$LVS --noheadings -o lv_size --units K $origin`
    if [ $? -ne 0 ]; then 
      /bin/echo "Could not determine size of $origin."   
      exit
    fi
       
    if [ ! -z $CVMFS_LVM_ROTATE ]; then
      num=`list_snapshots | /bin/awk '{LINES += 1} END {print LINES}'`
      if [ ! -z $num ]; then
        if [ $num -ge $CVMFS_LVM_ROTATE ]; then
          oldest=`list_snapshots | /bin/sort | /bin/grep -v "(published)" | /bin/sed -n 1p`
          /bin/echo "Removing $oldest..."
          remove_snapshot $oldest
        fi
      fi
    fi
    
    timestamp=`/bin/date "+%Y%m%d%H%M%S"`
    snapshot=$CVMFS_LV_TRUNK-$timestamp
    $LVCREATE -s -L $size -p r -n $snapshot $origin
    if [ $? -ne 0 ]; then 
      echo "Could not create snapshot $snapshot."   
      exit
    fi
    
    switch_snapshot $snapshot
  ;;
  switch)
    if [ $# -lt 2 ]; then
      usage
      exit
    fi
    
    snapshot=$2
    check_snapshot $snapshot
    result=$?
    if [ $result -eq 0 ]; then
      /bin/echo "This is not a snapshot."
      exit
    elif [ $result -eq 2 ]; then 
      /bin/echo "Snapshot is already published."
      exit
    fi
    
    switch_snapshot $snapshot
  ;;
  remove)
    if [ $# -lt 2 ]; then
      usage
      exit
    fi
    
    remove_snapshot $2
  ;;
  *)
    usage
    exit
  ;;   
esac
